package de.carcophan.archiver;

import com.google.inject.Inject;
import de.carcophan.archiver.util.FileWalker;
import de.carcophan.archiver.util.FileWalkerHandler;
import javafx.application.Application;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZArchiveEntry;
import org.apache.commons.compress.archivers.sevenz.SevenZOutputFile;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;

/**
 * Created by  on 15.04.2014.
 */
public class ArchiveWorker implements Runnable {

  private static final Logger logger = LogManager.getLogger(ArchiveWorker.class);

  @Inject
  private Config config;

  private BackupEventListener backupEventListener;

  public ArchiveWorker() {
  }

  @Override
  public void run() {
    logger.debug("run()");
    int interval = config.getBackupInterval() * 60 * 1000;
    String dest = config.getDestDir();
    final String src = config.getSrcDir();

    while (true) {
      try {
        final ZipArchiveOutputStream zipArchiveOutputStream = new ZipArchiveOutputStream(new File(dest + "/arch-" + System.currentTimeMillis() + ".zip"));
        FileWalker fileWalker = new FileWalker();
        fileWalker.doWalk(new File(src), new FileWalkerHandler() {
          @Override
          public void handle(File file) throws IOException {
            logger.trace("handle() - " + file);

            String filePath = file.getAbsolutePath();
            String base = filePath.replace(src, StringUtils.EMPTY);
            if (base.startsWith(file.separator)) {
              base = StringUtils.removeStart(base, File.separator);
            }

            ArchiveEntry archiveEntry = zipArchiveOutputStream.createArchiveEntry(file, base);
            zipArchiveOutputStream.putArchiveEntry(archiveEntry);
            zipArchiveOutputStream.write(IOUtils.toByteArray(new FileInputStream(file)));
            zipArchiveOutputStream.closeArchiveEntry();
          }
        });
        zipArchiveOutputStream.finish();
        zipArchiveOutputStream.close();

        notifyBackupEventListeners();

      } catch (Exception e) {
        logger.warn("error in ArchiveWorker", e);
      }
      try {
        logger.info("sleep: " + (interval / 1000) + " secs");
        Thread.sleep(interval);
      } catch (InterruptedException e) {
        logger.warn("Thread interrupted.", e);
        throw new RuntimeException(e);
      }

    }
  }

  private void notifyBackupEventListeners() {
    Calendar instance = Calendar.getInstance();
    String backupMessage = instance.getTime().toString();
    instance.add(Calendar.MINUTE, config.getBackupInterval());
    String futureMessage = instance.getTime().toString();
    logger.info("next Backup: " + futureMessage);
    backupEventListener.onBackupEvent(backupMessage, futureMessage);
  }

  public void setBackupEventListener(BackupEventListener backupEventListener) {
    this.backupEventListener = backupEventListener;
  }
}
